﻿namespace Leetcode.N1195;
using System.Threading;
public class FizzBuzz
{
    private int n;
    private AutoResetEvent fizz = new AutoResetEvent(false);
    private AutoResetEvent buzz = new AutoResetEvent(false);
    private AutoResetEvent fizzbuzz = new AutoResetEvent(false);
    private AutoResetEvent number = new AutoResetEvent(true);
    private int val = 1;

    public FizzBuzz(int n)
    {
        this.n = n;
    }

    // printFizz() outputs "fizz".
    public void Fizz(Action printFizz)
    {
        while (this.val <= this.n)
        {
            this.fizz.WaitOne();
            if (this.val > this.n)
            {
                break;
            }
            printFizz();
            this.val++;
            this.Release();
        }
    }

    // printBuzzz() outputs "buzz".
    public void Buzz(Action printBuzz)
    {
        while (this.val <= this.n)
        {
            this.buzz.WaitOne();
            if (this.val > this.n)
            {
                break;
            }
            printBuzz();
            this.val++;
            this.Release();
        }
    }

    // printFizzBuzz() outputs "fizzbuzz".
    public void Fizzbuzz(Action printFizzBuzz)
    {
        while (this.val <= this.n)
        {
            this.fizzbuzz.WaitOne();
            if (this.val > this.n)
            {
                break;
            }
            printFizzBuzz();
            this.val++;
            this.Release();
        }
    }

    // printNumber(x) outputs "x", where x is an integer.
    public void Number(Action<int> printNumber)
    {
        while (this.val <= this.n)
        {
            this.number.WaitOne();
            if (this.val > this.n)
            {
                break;
            }
            printNumber(this.val);
            this.val++;
            this.Release();
        }

    }

    private void Release()
    {
        if (this.val > n)
        {
            this.number.Set();
            this.fizz.Set();
            this.buzz.Set();
            this.fizzbuzz.Set();
            return;
        }

        if (this.val % 15 == 0)
        {
            this.fizzbuzz.Set();
        }
        else if (this.val % 3 == 0)
        {
            this.fizz.Set();
        }
        else if (this.val % 5 == 0)
        {
            this.buzz.Set();
        }
        else
        {
            this.number.Set();
        }
    }

}